﻿using System;
using System.Linq;
using System.Threading.Tasks;
using System.Net;
using Sustainalytics.Utils;
using Sustainalytics.Utils.WebApi.ErrorCodes;
using System.Web.Http;
using System.Net.Http;
using Sustainalytics.ProductInvolvement.BL;
using Sustainalytics.DataLayer;
using Sustainalytics.Entities.ProductInvolvement;
using System.Web.Http.Cors;

namespace Sustainalytics.ProductInvolvement.Service.Controllers
{
    [EnableCors(origins: "*", headers: "*", methods: "*")]
    [RoutePrefix("api/v1/inputfile")]
    [LogControllerFilter(true, true, false)]
    public class InputFileController: ApiController, IInputFileController
    {
        private readonly IFileRepository _fileRepository; 
        private readonly IProductInvolvementBussinesLogic _blLayer;
        private readonly ProductInvolvementSerilog _log;

        public InputFileController(IFileRepository filerep, IProductInvolvementBussinesLogic blLayer, ProductInvolvementSerilog  log)
        {
            _fileRepository = filerep;
            _blLayer = blLayer;
            _log = log;
        }

        [Route("")]        
        public HttpResponseMessage Get()
        {
            return Get(Guid.Empty, true);
        }

         [Route("id")]        
        public HttpResponseMessage Get(Guid id, bool includeAllFields, bool getLatest = true)
        {
            HttpResponseMessage response;
            try
            {
                if (getLatest)
                {
                    var piFile = _blLayer.ReadLatestInputFileHistory();
                    if (piFile == null)
                        response = Request.CreateResponse(HttpStatusCode.NotFound); 
                    else
                        response = Request.CreateResponse(HttpStatusCode.OK,  piFile ); 
                }
                else 
                {
                    response = Request.CreateResponse(HttpStatusCode.NotImplemented); 
                }
            }
            catch (Exception ex)
            {
                _log.Exception(ex);
                response = Request.CreateResponse(HttpStatusCode.InternalServerError, 
                    new { ErrorStatusCode = WebAPIGeneralErrorCodes.UnhandledException });
            }            
            return response;
        }

        [Route("")]
        public Task<HttpResponseMessage> Post()
        {
            try
            {
                // put the file in mongo
                var id = Guid.NewGuid();
                var filename    = Request.Content.Headers.ContentDisposition.FileName;
                if (filename.StartsWith("\""))
                    filename = filename.Substring(1);

                if (filename.EndsWith("\""))
                    filename = filename.Substring(0, filename.Length - 2);


                var contentType = Request.Content.Headers.ContentType.ToString();
                var mongoData   = _fileRepository.UploadFile(id, filename, contentType);

                _log.UploadFiles(filename, contentType, id);

                var result = Request.Content.ReadAsStreamAsync()
                    .ContinueWith(task =>
                                    {
                                         
                                        if (task.IsCanceled || task.IsFaulted)
                                            throw new HttpRequestException();

                                        try
                                        {
                                            using (mongoData.Item1)
                                            {
                                                task.Result.CopyTo(mongoData.Item1);
                                            }

                                            using (var downloadStream = _fileRepository.GetDownloadStream(mongoData.Item2).Item1)
                                            {
                                                ValidationResult vResult;
                                                var pifile = _blLayer.CreateAndValidateInputFile(mongoData.Item2, downloadStream, filename, out vResult);

                                                var isValid = false;
                                                var details = "Validation failure";
                                                var newest = pifile.History.LastOrDefault();

                                                if (newest != null)
                                                {
                                                    isValid = (newest.Status == PIUploadStatus.UploadValid);
                                                    details = newest.Details;
                                                }

                                                return Request.CreateResponse(HttpStatusCode.OK,
                                                        new
                                                        {
                                                            id = pifile.Id,
                                                            isValid = isValid,
                                                            details = details
                                                        });
                                            }
                                        }
                                        catch(Exception ex)
                                        {
                                            _log.Exception(ex);
                                            return  Request.CreateResponse(HttpStatusCode.InternalServerError,
                                                new { ErrorStatusCode = WebAPIGeneralErrorCodes.UnhandledException });
                                        }
                                    });

                return (Task<HttpResponseMessage>)result;
            }
            catch (Exception ex)
            {
                _log.Exception(ex);
                return (new Task<HttpResponseMessage>(() => Request.CreateResponse(HttpStatusCode.InternalServerError,
                    new { ErrorStatusCode = WebAPIGeneralErrorCodes.UnhandledException })));
            }
        }

        [Route("")]
        public HttpResponseMessage Patch([FromBody] PIInputFilePatchOpDto patch)
        {
            HttpResponseMessage response;
            try
            {
                if (patch.Verb.ToUpperInvariant() == "PATCH" && patch.Canceled)
                {
                    var ok = _blLayer.CancelInputFile(patch.ResourceId);
                    response = Request.CreateResponse(ok ? HttpStatusCode.NoContent : HttpStatusCode.InternalServerError);
                }
                else
                {
                    response = Request.CreateResponse(HttpStatusCode.NotImplemented, "Only support PATCH with Canceled = true");
                }
            }
            catch (ResourceNotFound ex)
            {
                _log.Exception(ex);
                return Request.CreateResponse(HttpStatusCode.NotFound,
                                    new { ErrorStatusCode = WebAPIGeneralErrorCodes.ResourceNotFound, Input = patch });
            }
            catch (Exception ex)
            {
                _log.Exception(ex);
                return Request.CreateResponse(HttpStatusCode.InternalServerError,
                                    new { ErrorStatusCode = WebAPIGeneralErrorCodes.UnhandledException, Input = patch });
            }
            return response;
        }

    }
}
